package shiyl.use.springboot.loadbalance.impl;


import shiyl.use.springboot.loadbalance.AbstractLoadBalancePolicy;
import shiyl.use.springboot.loadbalance.ILoader;
import shiyl.use.springboot.loadbalance.POLICY;
import shiyl.use.springboot.utils.AtomicPositiveInteger;

import java.util.ArrayList;
import java.util.List;

/**
 * 轮询负载策略
 * 说明：
 * 首先也是判断权重是否一致，如果一致，通过维护一个 AtomicInteger 的增长 进行取模乱来轮训。
 * 如果权重不一致，通过维护一个 AtomicInteger 的增长 与最大权重取模作为当前权重，然后获取大于当前权重的列表作为调用者列表，然后进行取模轮训
 *
 * @author dubbo
 */
public class RoundRobinPolicy extends AbstractLoadBalancePolicy {

    private final AtomicPositiveInteger sequece = new AtomicPositiveInteger();
    private final AtomicPositiveInteger weightSequece = new AtomicPositiveInteger();

    /**
     * 执行负载策略选择负载点并返回
     *
     * @param loaders
     * @return
     */
    @Override
    protected <T> ILoader<T> doPolicySelect(List<ILoader<T>> loaders) {
        // 总个数
        int length = loaders.size();
        // 最大权重
        int maxWeight = 0;
        // 最小权重
        int minWeight = Integer.MAX_VALUE;

        for (int i = 0; i < length; i++) {

            // 权重
            int weight = loaders.get(i).getWeight();
            // 累计最大权重
            maxWeight = Math.max(maxWeight, weight);
            // 累计最小权重
            minWeight = Math.min(minWeight, weight);
        }

        // 权重不一样
        if (maxWeight > 0 && minWeight < maxWeight) {
            int currentWeight = weightSequece.getAndIncrement() % maxWeight;
            List<ILoader<T>> weightNodes = new ArrayList<>();
            for (ILoader node : loaders) {
                if (node.getWeight() > currentWeight) {
                    weightNodes.add(node);
                }
            }
            int weightLength = weightNodes.size();
            if (weightLength == 1) {
                return weightNodes.get(0);
            } else if (weightLength > 1) {
                loaders = weightNodes;
                length = loaders.size();
            }
        }

        // 取模轮询
        return loaders.get(sequece.getAndIncrement() % length);
    }

    /**
     * 策略名称
     *
     * @return
     */
    @Override
    public POLICY getPolicyName() {
        return POLICY.ROUNDROBIN;
    }
}
